/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sdc;

import java.awt.Color;
import java.io.*;
import java.net.*;
import java.util.regex.*;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.Random;
import javax.swing.JOptionPane;

/**
 *
 * @author Don
 */
public class Scraper implements Runnable {
    
    private ScheduledThreadPoolExecutor timer;
    private String threadURL;
    private ScraperMessageReceiver messageReceiver;
    private long lastPost = 0;
    private Color currentColor, colorOne = new Color(58, 195, 212), colorTwo = new Color(219, 137, 26);
    
    public Scraper(ScraperMessageReceiver messageReceiver) {
        this.messageReceiver = messageReceiver;
    }
    
    public void start() {
        if (!this.isRunning()) {
            this.timer = new ScheduledThreadPoolExecutor(1);
            this.timer.schedule(this, 1000, TimeUnit.MILLISECONDS);
        }
    }
    
    public void run() {
        this.scrapeURL();
    }
    
    public boolean isRunning() {
        return this.timer != null && (this.timer.getTaskCount() - this.timer.getCompletedTaskCount()) <= 0;
    }
    
    public String getURL() {
        return this.threadURL;
    }
    
    public void setURL(String url) {
        synchronized (this) {
            this.threadURL = url;
        }
    }
    
    private void scrapeURL() {
        synchronized (this) {
            try {
                if (this.threadURL == null || this.threadURL.equals("")) return;
                this.messageReceiver.statusUpdate("Looking for new posts...");
                Pattern currentPagePattern = Pattern.compile("<span class=\"pagenav_result_text\"><strong>Page ([0-9]*) of [0-9]*</strong>[^<]*</span>");
                Pattern lastPattern = Pattern.compile("<a class=\"search_pagenav search_pagenav_text\" href=\"([^\"]*)\">Last</a>");
                Pattern latestPagePattern = Pattern.compile("<a class=\"search_pagenav\" href=\"([^\"]*)\"[^>]*>(?:<\\!---[0-9]*-->)?([0-9]*)</a>");
                Pattern postPattern = Pattern.compile("<div class=\"sd_postbit(?: sd_postbit_last)?\" id=\"[^\"]*\">.*?<!-- / message -->");
                boolean lastPageFound = false, newPageFound = false;
                BufferedReader reader = new BufferedReader(new InputStreamReader(new URL(this.threadURL).openStream()));
                String websiteText = new String();
                while (reader.ready()) {
                    websiteText += reader.readLine();
                }
                reader.close();
                // Check if we can navigate to the last page
                Matcher matcher = lastPattern.matcher(websiteText);
                while (matcher.find()) {
                    String pageURL = matcher.group(1);
                    // Remove leading slash
                    if (pageURL.startsWith("/")) {
                        pageURL = pageURL.substring(1);
                    }
                    // Remove html encoded ampersands
                    pageURL = pageURL.replace("&amp;", "&");
                    // Set the new URL
                    this.threadURL = "http://www.slickdeals.net/" + pageURL;
                    lastPageFound = true;
                }
                // No last page link found
                if (!lastPageFound) {
                    // Get the current page
                    int currentPage = 0;
                    matcher = currentPagePattern.matcher(websiteText);
                    while (matcher.find()) {
                        currentPage = Integer.parseInt(matcher.group(1));
                    }
                    // Get the latest page
                    matcher = latestPagePattern.matcher(websiteText);
                    while (matcher.find()) {
                        String pageURL = matcher.group(1);
                        String pageNum = matcher.group(2);
                        if (Integer.parseInt(pageNum) > currentPage) {
                            // Remove leading slash
                            if (pageURL.startsWith("/")) {
                                pageURL = pageURL.substring(1);
                            }
                            // Remove html encoded ampersands
                            pageURL = pageURL.replace("&amp;", "&");
                            // Set the new URL
                            this.threadURL = "http://www.slickdeals.net/" + pageURL;
                            newPageFound = true;
                        }
                    }
                }
                // Parse the posts
                Color postColor = this.getColor();
                matcher = postPattern.matcher(websiteText);
                while(matcher.find()) {
                    Post post = new Post(matcher.group(), postColor);
                    if (post.number > this.lastPost) {
                        this.messageReceiver.receivePost(post);
                        this.lastPost = post.number;
                    }
                }
                this.messageReceiver.statusUpdate("Taking a break...");
                // Schedule another search
                if (lastPageFound || newPageFound) {
                    this.timer.schedule(this, 1000, TimeUnit.MILLISECONDS);
                }
                else {
                    this.timer.schedule(this, 15000, TimeUnit.MILLISECONDS);
                }
            }
            catch (MalformedURLException ex) {
                JOptionPane.showMessageDialog(null, ex.toString(), "Exception", JOptionPane.ERROR_MESSAGE);
                this.messageReceiver.statusUpdate("Trying again soon...");
                this.timer.schedule(this, 15000, TimeUnit.MILLISECONDS);
            }
            catch (IllegalStateException ex) {
                JOptionPane.showMessageDialog(null, ex.toString(), "Exception", JOptionPane.ERROR_MESSAGE);
                this.messageReceiver.statusUpdate("Trying again soon...");
                this.timer.schedule(this, 15000, TimeUnit.MILLISECONDS);
            }
            catch (IOException ex) {
                JOptionPane.showMessageDialog(null, ex.toString(), "Exception", JOptionPane.ERROR_MESSAGE);
                this.messageReceiver.statusUpdate("Trying again soon...");
                this.timer.schedule(this, 15000, TimeUnit.MILLISECONDS);
            }
            catch (Exception ex) {
                JOptionPane.showMessageDialog(null, ex.toString(), "Exception", JOptionPane.ERROR_MESSAGE);
                this.messageReceiver.statusUpdate("Trying again soon...");
                this.timer.schedule(this, 15000, TimeUnit.MILLISECONDS);
            }
        }
    }
    
    private Color getColor() {
        if (this.currentColor == null) {
            this.currentColor = colorOne;
            return this.currentColor;
        }
        if (this.currentColor.equals(colorOne)) {
            this.currentColor = colorTwo;
            return this.currentColor;
        }
        else {
            this.currentColor = colorOne;
            return this.currentColor;
        }
    }
}
